/* 部署 */
const archiver = require('archiver')
const fs = require('fs')
const ora = require('ora')
const inquirer = require('inquirer')
const { NodeSSH } = require('node-ssh')
const {
  resolve,
  exit,
  succeed,
  error,
  info
} = require('../utils/index')

const list = [
  {
    fn: selectEnv
  },
  {
    fn: inputServerInfo
  },
  {
    loading: 'ssh连接中...',
    succeed: 'ssh连接成功!',
    fn: connectSSH
  },
  {
    fn: selectEnvEntry
  },
  {
    text: '(1) 压缩打包项目',
    loading: '压缩中...',
    succeed: '压缩成功!',
    fn: compressDir
  },
  {
    text: '(2) 上传项目文件',
    loading: '上传文件中...',
    succeed: '上传文件成功',
    fn: uploadLocalFile
  },
  {
    text: '(3) 删除远程文件',
    loading: '删除中...',
    succeed: '删除成功',
    fn: removeRemoteFile
  },
  {
    text: '(4) 解压远程文件',
    loading: '解压中...',
    succeed: '解压成功',
    fn: unzipRemoteFile
  },
  {
    text: '(5) 删除本地压缩包',
    loading: '删除中...',
    succeed: '删除成功',
    fn: removeLocalFile
  },
  {
    text: '(6) 断开ssh连接',
    loading: '断开ssh连接中...',
    succeed: '断开ssh成功',
    fn: disconnectSSH
  },
]
const ssh = new NodeSSH()

let projects // 本次选中的项目

let env // 选中的环境

let configData // deploy配置数据

let server = { username: '', password: '' } // 服务器账号和密码

module.exports = async function() {
  try {
    /* 读取config文件 */
    configData = require(resolve('micro-config')).deployConfig
    for (const key in list) {
      const item = list[ key ]

      /* 步骤提示文字 */
      item.text && console.log(item.text)
      /* 加载动画 */
      let spinner

      if (item.loading) {
        spinner = ora(item.loading)
        spinner.start()
      }
      const log = await item.fn()

      /* 关闭动画*/
      spinner && spinner.stop()
      /* 是否后置打印 */
      if (Array.isArray(log)) {
        log.forEach(item => info(item))
      }
      /* 成功提示 */
      item.succeed && succeed(item.succeed)
    }
    succeed('部署完成!')
  } catch (err) {
    error(err)
    process.exit(1)
  }
}

/**
 * 输入服务器账号和密码
 */
async function inputServerInfo() {
  server = await inquirer.prompt([
    {
      type: 'input',
      name: 'username',
      message: '请输入服务器账号'
    },
    {
      type: 'password',
      name: 'password',
      message: '请输入服务器密码'
    }
  ])
}

/**
 * 选择环境
 */
async function selectEnv() {
  env = (await require('../utils/selectEnv')('请选择部署环境')).env
}

/**
 * ssh连接
 */
async function connectSSH() {
  const spinner = ora('ssh连接中')

  try {

    const { host, port } = configData[ env ]

    await ssh.connect({ host, port, ...server })
  } catch (e) {
    error(e)
    process.exit(1)
  }
  spinner.stop()
}

/**
 * 选择发布环境和打包的项目
 */
async function selectEnvEntry() {
  const res = await require('./build')('请选择需要部署的项目:', env)

  projects = res.projects
}

/**
 * 压缩包
 */
async function compressDir() {
  try {
    await Promise.all(projects.map(item => new Promise((resolve, reject) => {
      const archive = archiver('zip', {
        zlib: { level: 9 }
      }).on('error', (e) => {
        error(e)
      })

      const output = fs
        .createWriteStream(`${ process.cwd() }/${ item.src }.zip`)
        .on('close', (e) => {
          if (e) {
            error(`打包zip出错: ${ e }`)
            reject(e)
            exit(1)
          } else {
            resolve()
          }
        })

      archive.pipe(output)
      archive.directory(item.src, false)
      archive.finalize()
    })))
  } catch (e) {
    error(e)
    process.exit(1)
  }
}

/**
 * 上传文件
 */
async function uploadLocalFile() {
  const { webDir } = configData[ env ]

  try {
    await Promise.all(projects.map(item => {
      const remotePath = `${ webDir }/${ item.entry }.zip`
      const localPath = `${ process.cwd() }/${ item.distPath }.zip`

      /* 压缩包上传到对应的项目文件夹下，与项目文件夹同名 */
      return ssh.putFile(localPath, remotePath, null, {
        concurrency: 1
      })
    }))
  } catch (e) {
    error(`上传文件失败: ${ e }`)
    process.exit(1)
  }
}

/**
 * 删除原来远程的目录文件
 */
async function removeRemoteFile() {
  try {
    const { webDir } = configData[ env ]

    await Promise.all(projects.map(item => {
      const remotePath = `${ webDir }/${ item.entry }`

      return ssh.execCommand(`rm -rf ${ remotePath }`)
    }))
  } catch (e) {
    error(e)
    process.exit(1)
  }
}

/**
 * 解压远程文件
 */
async function unzipRemoteFile() {
  const log = []

  try {
    const { webDir } = configData[ env ]

    await Promise.all(projects.map(item => {
      const remotePath = `${ webDir }/${ item.entry }`

      log.push(`${ item.name } 已部署至 ${ remotePath }`)

      return ssh.execCommand(`unzip -o ${ remotePath }.zip -d ${ remotePath } && rm -rf ${ remotePath }.zip`)
    }))
  } catch (e) {
    error(e)
    process.exit(1)
  }
  return log
}

/**
 * 删除本地打包文件
 */
function removeLocalFile() {
  try {
    projects.forEach(item => {
      fs.unlinkSync(`${ process.cwd() }/${ item.distPath }.zip`)
    })
  } catch (e) {
    error(e)
    process.exit(1)
  }
}

/**
 * 断开ssh连接
 */
function disconnectSSH() {
  ssh.dispose()
}
